package com.zyk.scaffold.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zyk.scaffold.common.enums.TenantRoleTypeEnum;
import com.zyk.scaffold.common.enums.TenantTypeEnum;
import com.zyk.scaffold.common.enums.TenantUserTypeEnum;
import com.zyk.scaffold.common.utils.AssertUtil;
import com.zyk.scaffold.common.utils.BeanCopyUtil;
import com.zyk.scaffold.user.controller.tenant.TenantCreatRequest;
import com.zyk.scaffold.user.controller.tenant.TenantResponse;
import com.zyk.scaffold.user.controller.tenant.TenantUpdateRequest;
import com.zyk.scaffold.user.domain.FunctionMessage;
import com.zyk.scaffold.user.entity.*;
import com.zyk.scaffold.user.mapper.TenantMapper;
import com.zyk.scaffold.user.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 租户表 服务实现类
 * </p>
 *
 * @author zhouyk
 * @since 2022-11-04
 */
@Service
public class TenantServiceImpl extends ServiceImpl<TenantMapper, Tenant> implements TenantService {

    @Autowired
    private TenantFunctionService tenantFunctionService;

    @Autowired
    private TenantRoleService tenantRoleService;

    @Autowired
    private TenantRoleFunctionService tenantRoleFunctionService;

    @Autowired
    private TenantUserRoleService tenantUserRoleService;

    @Autowired
    private TenantUserService tenantUserService;

    @Autowired
    private UserService userService;

    @Override
    public List<Tenant> getTenantInfos() {
        return this.list(Wrappers.lambdaQuery(Tenant.class).eq(Tenant::getDeleted, Boolean.FALSE));
    }

    @Override
    public Boolean create(TenantCreatRequest tenantCreatRequest, Long userId) {
        String name = tenantCreatRequest.getName().trim();
        AssertUtil.isTrue(valitedTenantName(name, null), "租户名称已存在(" + name + ")");
        // 1、创建租户
        String tenantCode = getTenantCode();
        Tenant tenant = new Tenant();
        tenant.setCode(tenantCode);
        tenant.setCreateUser(userId);
        tenant.setUpdateUser(userId);
        tenant.setName(name);
        tenant.setType(TenantTypeEnum.BUSINESS.getCode());
        boolean save = this.save(tenant);
        AssertUtil.isTrue(save, "租户创建失败");

        // 2、绑定租户功能关系
        List<Long> functionIds = tenantCreatRequest.getFunctionIds().stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<TenantFunction> tenantFunctions = functionIds.stream().map(functionId -> {
            TenantFunction tenantFunction = new TenantFunction();
            tenantFunction.setFunctionId(functionId);
            tenantFunction.setCreateUser(userId);
            tenantFunction.setUpdateUser(userId);
            tenantFunction.setTenantCode(tenantCode);
            return tenantFunction;
        }).collect(Collectors.toList());
        save = tenantFunctionService.saveBatch(tenantFunctions);
        AssertUtil.isTrue(save, "绑定租户功能关系失败");

        // 3、创建租户系统管理角色
        TenantRole tenantRole = new TenantRole();
        tenantRole.setTenantCode(tenantCode);
        tenantRole.setCreateUser(userId);
        tenantRole.setUpdateUser(userId);
        tenantRole.setEnable(Boolean.TRUE);
        tenantRole.setName("系统管理员");
        tenantRole.setType(TenantRoleTypeEnum.TENANT_ROLE_TYPE_BUSINESS.getCode());
        tenantRole.setRemark("该角色由系统自动创建");
        save = tenantRoleService.save(tenantRole);
        AssertUtil.isTrue(save, "创建租户系统管理角色失败");

        // 绑定角色租户功能关系失
        List<TenantRoleFunction> tenantRoleFunctions = tenantFunctions.stream().map(item -> {
            TenantRoleFunction tenantRoleFunction = new TenantRoleFunction();
            tenantRoleFunction.setTenantFunctionId(item.getId());
            tenantRoleFunction.setTenantRoleId(tenantRole.getId());
            tenantRoleFunction.setCreateUser(userId);
            return tenantRoleFunction;
        }).collect(Collectors.toList());
        save = tenantRoleFunctionService.saveBatch(tenantRoleFunctions);
        AssertUtil.isTrue(save, "绑定角色租户功能关系失败");

        List<TenantUser> administratorTenantUsers = new ArrayList<>();
        List<TenantUser> tenantUsers = new ArrayList<>();

        // 初始管理员账号列表
        if(CollectionUtils.isNotEmpty(tenantCreatRequest.getAdminUserIds())){
            administratorTenantUsers = tenantCreatRequest.getAdminUserIds().stream().map(item -> {
                TenantUser tenantUser = new TenantUser();
                tenantUser.setTenantCode(tenantCode);
                tenantUser.setCreateUser(userId);
                tenantUser.setUpdateUser(userId);
                tenantUser.setType(TenantUserTypeEnum.TENANT_USER_TYPE_BUSINESS.getCode());
                tenantUser.setEnable(Boolean.TRUE);
                tenantUser.setUserId(item);
                return tenantUser;
            }).collect(Collectors.toList());
            tenantUsers.addAll(administratorTenantUsers);
        }

        // 内部租户账管理员号列表
        if(CollectionUtils.isNotEmpty(tenantCreatRequest.getInnerAdminUserIds())){
            administratorTenantUsers = tenantCreatRequest.getInnerAdminUserIds().stream().map(item -> {
                TenantUser tenantUser = new TenantUser();
                tenantUser.setTenantCode(tenantCode);
                tenantUser.setCreateUser(userId);
                tenantUser.setUpdateUser(userId);
                tenantUser.setType(TenantUserTypeEnum.TENANT_USER_TYPE_INNER.getCode());
                tenantUser.setEnable(Boolean.TRUE);
                tenantUser.setUserId(item);
                return tenantUser;
            }).collect(Collectors.toList());
            tenantUsers.addAll(administratorTenantUsers);
        }

        // 绑定用户租户关系
        if(CollectionUtils.isNotEmpty(tenantUsers)){
            save = tenantUserService.saveBatch(tenantUsers);
            AssertUtil.isTrue(save, "绑定用户租户关系失败");
        }

        // 绑定用户角色关系
        if(CollectionUtils.isNotEmpty(administratorTenantUsers)){
            List<TenantUserRole> tenantUserRoles = administratorTenantUsers.stream().map(tenantUser -> {
                TenantUserRole tenantUserRole = new TenantUserRole();
                tenantUserRole.setTenantUserId(tenantUser.getId());
                tenantUserRole.setTenantRoleId(tenantRole.getId());
                tenantUserRole.setCreateUser(userId);
                return tenantUserRole;
            }).collect(Collectors.toList());
            save = tenantUserRoleService.saveBatch(tenantUserRoles);
            AssertUtil.isTrue(save, "绑定用户角色关系失败");
        }

        return Boolean.TRUE;
    }

    private boolean valitedTenantName(String name, Long excludeId) {
        LambdaQueryWrapper<Tenant> tenantLambdaQueryWrapper = new LambdaQueryWrapper<>();
        tenantLambdaQueryWrapper.eq(Tenant::getName, name).eq(Tenant::getDeleted, Boolean.FALSE);
        if(excludeId != null){
            tenantLambdaQueryWrapper.ne(Tenant::getId, excludeId);
        }
        int count = this.count(tenantLambdaQueryWrapper);
        if(count == 0){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    private String getTenantCode() {
        for (;;){
            String tenantCode = RandomStringUtils.randomAlphanumeric(10).toUpperCase();
            int count = this.count(new LambdaQueryWrapper<Tenant>().eq(Tenant::getCode, tenantCode));
            if(count == 0){
                return tenantCode;
            }
        }
    }

    @Override
    public Boolean update(TenantUpdateRequest tenantUpdateRequest, Long userId) {
        String name = tenantUpdateRequest.getName().trim();
        Long id = tenantUpdateRequest.getId();
        AssertUtil.isTrue(valitedTenantName(name, id), "租户名称已存在(" + name + ")");
        // 获取租户信息
        Tenant tenant = this.getById(id);
        AssertUtil.notIsNull(tenant, "租户ID(" + id + "),不存在!");
        Boolean save = true;
        String tenantCode = tenant.getCode();

        // 修改name
        if(StringUtils.isNotEmpty(name) && !StringUtils.equals(name, tenant.getName())){
            tenant.setName(name);
            tenant.setUpdateUser(userId);
            tenant.setUpdateTime(LocalDateTime.now());
            this.updateById(tenant);
        }
        // 获取原有租户功能IDs
        List<TenantFunction> tenantFunctionOlds = tenantFunctionService.getTenantFunctionsByTenantCode(tenantCode);
        List<Long> targetFunctionIds = tenantUpdateRequest.getFunctionIds();

        // 计算删除、新增的功能ID
        List<Long> deletedFunctionIds = new ArrayList<>();
        List<Long> functionIds = new ArrayList<>();
        for (TenantFunction tenantFunction : tenantFunctionOlds) {
            functionIds.add(tenantFunction.getFunctionId());
            if(targetFunctionIds.contains(tenantFunction.getFunctionId())){
                continue;
            }
            deletedFunctionIds.add(tenantFunction.getFunctionId());
        }
        List<Long> addFunctionIds = new ArrayList<>(targetFunctionIds);
        addFunctionIds.removeAll(functionIds);

        // 新增功能
        if (CollectionUtils.isNotEmpty(addFunctionIds)){
            List<TenantFunction> tenantFunctions = addFunctionIds.stream().map(functionId -> {
                TenantFunction tenantFunction = new TenantFunction();
                tenantFunction.setFunctionId(functionId);
                tenantFunction.setCreateUser(userId);
                tenantFunction.setUpdateUser(userId);
                tenantFunction.setTenantCode(tenantCode);
                return tenantFunction;
            }).collect(Collectors.toList());
            save = tenantFunctionService.saveBatch(tenantFunctions);
            AssertUtil.isTrue(save, "绑定租户功能关系失败");
        }

        // 删除功能
        if (CollectionUtils.isNotEmpty(deletedFunctionIds)){
            // 处理租户下的删除功能IDS
            UpdateWrapper<TenantFunction> tenantFunctionUpdateWrapper = new UpdateWrapper<>();
            LambdaUpdateWrapper<TenantFunction> lambdaUpdateWrapper = tenantFunctionUpdateWrapper.lambda()
                    .set(TenantFunction::getUpdateUser, userId)
                    .set(TenantFunction::getUpdateTime, LocalDateTime.now())
                    .set(TenantFunction::getDeleted, true)
                    .eq(TenantFunction::getTenantCode, tenantCode)
                    .in(TenantFunction::getFunctionId, deletedFunctionIds);
            save = tenantFunctionService.update(lambdaUpdateWrapper);
            AssertUtil.isTrue(save, "删除租户功能关系失败");
            // 处理角色下的删除功能IDS
            tenantRoleFunctionService.deleteByTenantCodeFunctionIds(tenantCode, deletedFunctionIds);
        }
        return save;
    }

    @Override
    public List<TenantResponse> listInofs() {
        List<Tenant> tenantInfos = this.getTenantInfos();
        List<TenantResponse> tenantResponses = new ArrayList<>();
        List<String> tenantCodes = tenantInfos.stream().map(Tenant::getCode).distinct().collect(Collectors.toList());
        List<FunctionMessage> functionMessages = tenantFunctionService.queryTenantCodesFunction(tenantCodes);

        Map<String, List<FunctionMessage>> mapTenantCode2s = functionMessages.stream().collect(Collectors.groupingBy(FunctionMessage::getTenantCode));
        tenantResponses.addAll(BeanCopyUtil.copyListProperties(tenantInfos, TenantResponse::new, (old, news) -> {
            String code = news.getCode();
            List<FunctionMessage> functionMessageReponsesTmp = mapTenantCode2s.get(code);
            if(functionMessageReponsesTmp == null){
                functionMessageReponsesTmp = Collections.emptyList();
            }
            news.setFunctions(functionMessageReponsesTmp);
        }));
        return tenantResponses;
    }

    @Override
    public List<Tenant> getTenantInfosByType(Integer type) {
        return this.getTenantInfos().stream().filter(tenant -> type.equals(tenant.getType())).collect(Collectors.toList());
    }
}
